package com.husd.framework.apidoc;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.husd.framework.autocode.dto.ClassDefine;
import com.husd.framework.autocode.dto.ClassFieldDefine;
import com.husd.framework.ddl.AutoCodeUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author shengdonghu@126.com
 * @date 2023/10/10 10:05
 */
public class JsonApiDocUtil {

    final boolean repeat = false;
    Stack<JsonStackItem> stack = new Stack<>();
    String packageName;

    Set<String> classNameSet = new HashSet<>();

    public JsonApiDocUtil(String json,
                          String packageName,
                          String className) {
        JSONObject jsonObject = JSONObject.parseObject(json, Feature.OrderedField);
        JsonStackItem jsonStackItem = new JsonStackItem(jsonObject, className, "", null);
        this.stack.push(jsonStackItem);
        this.packageName = packageName;
    }

    public ConvertResp convert() {

        List<String> allPath = new ArrayList<>();
        if (stack.isEmpty()) {
            return null;
        }
        JsonStackItem jsonStackItem = stack.pop();
        JSON current = jsonStackItem.getJson();
        String className = jsonStackItem.getClassName();
        String prePath = jsonStackItem.getPath();
        List<ClassDefine> res = new ArrayList<>();

        if (current instanceof JSONObject) {

            JSONObject jsonObject = (JSONObject) current;
            ClassDefine classDefine = new ClassDefine();

            classDefine.setPackageName(packageName);
            classDefine.setClassName(jsonStackItem.getClassName());
            classDefine.setClassType("class");
            List<String> importList = new ArrayList<>();
            importList.add("import java.util.List");
            importList.add("import com.alibaba.fastjson.annotation.JSONField");
            importList.add("import com.vevor.open.sdk.allegro.domain.OpenJsonPath");
            classDefine.setImportList(importList);
            classDefine.setAnnotationList(null);

            List<String> annoList = new ArrayList<>();
            annoList.add("@Data\n");
            classDefine.setAnnotationList(annoList);


            // 设置field
            Set<Map.Entry<String, Object>> fieldSet = jsonObject.entrySet();
            // 这种要看有几个元素 如果有多个元素 就递归处理
            // 如果没有子元素 就需要特殊处理
            if (CollectionUtils.isNotEmpty(fieldSet)) {
                List<ClassFieldDefine> fieldList = classDefine.getFieldList();
                if (fieldList == null) {
                    fieldList = new ArrayList<>();
                }
                for (Map.Entry<String, Object> entry : fieldSet) {
                    // 要考虑这个元素 是不是可以有多个
                    final String key = entry.getKey();

                    String currentPath = StringUtils.isBlank(prePath) ? key : prePath + ":" + key;

                    Object val = entry.getValue();
                    ClassFieldDefine classFieldDefine = defaultElementField(entry, currentPath);
                    allPath.add(classFieldDefine.getExt());
                    fieldList.add(classFieldDefine);

                    // 类名字可能会重复 所以需要处理
                    if (classFieldDefine.isComplex()) {
                        if (val instanceof JSONObject) {
                            pushClass2Stack(new JsonStackItem((JSONObject) val, classFieldDefine.getClassTypeName(), currentPath, classFieldDefine));
                        } else if (val instanceof JSONArray) {
                            //数组的话 要找真实的类型
                            pushClass2Stack(new JsonStackItem((JSONArray) val, classFieldDefine.getClassTypeName(), currentPath, classFieldDefine));
                        }
                    }
                }
                classDefine.setFieldList(fieldList);
                res.add(classDefine);
            } else {
            }
        } else if (current instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) current;
            Object first = jsonArray.get(0);
            if (first == null) {
                throw new RuntimeException("属性:" + current.toJSONString() + " 是数组 但是没有类型信息");
            } else {
                if (first instanceof JSONObject) {
                    JSONObject firstJsonObject = (JSONObject) first;
                    pushClass2Stack(new JsonStackItem(firstJsonObject, jsonStackItem.getClassName(), prePath, null));
                } else if (first instanceof JSONArray) {
                    pushClass2Stack(new JsonStackItem((JSONArray) first, jsonStackItem.getClassName(), prePath, null));
                } else {
                    // 其它类型就不处理了
                }
            }
        }

        while (stack.isEmpty() == false) {
            ConvertResp convertResp = this.convert();
            List<ClassDefine> subClassDefineList = convertResp.getClassDefineList();
            List<String> subAllPath = convertResp.getAllPath();
            if (CollectionUtils.isNotEmpty(subClassDefineList)) {
                res.addAll(subClassDefineList);
                allPath.addAll(subAllPath);
            }
        }

        return new ConvertResp(res, allPath);
    }

    private void pushClass2Stack(JsonStackItem jsonStackItem) {

        // classname可能会重复 所以需要处理为不重复的
        String className = jsonStackItem.getClassName();
//        int index = 0;
//        while (classNameSet.contains(className)) {
//            className = className + index;
//            index++;
//        }
//        classNameSet.add(className);
//        jsonStackItem.setClassName(className);
        stack.push(jsonStackItem);
    }

    private ClassFieldDefine defaultElementField(Map.Entry<String, Object> entry, final String currentPath) {

        final String key = entry.getKey();
        final Object val = entry.getValue();
        boolean arrayType = false;
        ClassFieldDefine classFieldDefine = new ClassFieldDefine();
        final String originalType = AutoCodeUtil.preDealKey(key);

        // 加工之后 不带类型 属于类的名字
        String type = originalType;
        if (val instanceof JSONArray) {
            // 空就是说明是复合类型 需要是类 类的名字需要单独处理 生成
            JSONArray jsonArray = (JSONArray) val;
            if (jsonArray.size() == 0) {
                throw new RuntimeException("属性 key:" + key + " 类型是一个数组 但是没给明确的类型");
            }
            type = generateClassName(jsonArray, originalType);
            classFieldDefine.setComment(String.valueOf(val));
            arrayType = true;
        } else if (val instanceof JSONObject) {
            type = generateClassName(originalType);
            arrayType = false;
        } else if (val instanceof Integer) {
            type = "java.lang.Integer";
            classFieldDefine.setComment(String.valueOf(val));
        } else if (val instanceof Long) {
            type = "java.lang.Long";
            classFieldDefine.setComment(String.valueOf(val));
        } else if (val instanceof String) {
            type = "java.lang.String";
            classFieldDefine.setComment(String.valueOf(val));
        } else if (val instanceof Boolean) {
            type = "java.lang.Boolean";
            classFieldDefine.setComment(String.valueOf(val));
        } else if(val instanceof BigDecimal) {
            type = "java.math.BigDecimal";
            classFieldDefine.setComment(String.valueOf(val));
        } else if (val instanceof LinkedHashMap) {
            LinkedHashMap<String, Object> linkedHashMap = (LinkedHashMap) val;
            for (Map.Entry<String, Object> ee : linkedHashMap.entrySet()) {
                String eeKey = ee.getKey();
                Object eeVal = ee.getValue();
                if (eeVal instanceof Integer) {
                    type = "java.lang.Integer";
                } else if (eeVal instanceof Long) {
                    type = "java.lang.Long";
                } else if (eeVal instanceof String) {
                    type = "java.lang.String";
                } else if (eeVal instanceof Boolean) {
                    type = "java.lang.Boolean";
                } else if(eeVal instanceof BigDecimal) {
                    type = "java.math.BigDecimal";
                } else {
                    type = "java.lang.String";
                }
                classFieldDefine.setComment(String.valueOf(eeVal));
                break;
            }
        }

        //classFieldDefine.setFieldName(StringUtils.uncapitalize(localName));
        // classFieldDefine.setFieldName(localName);
        String t = "@JSONField(name=\"%s\")\n     @OpenJsonPath(path = \"%s\")";
        classFieldDefine.setFieldAnnotation(String.format(t, key, currentPath));
        classFieldDefine.setExt(currentPath);
        boolean complex = !AutoCodeUtil.isBaseType(type);
        classFieldDefine.setComplex(complex);

        // 修正下FieldType 子元素的类名字 可能会重复 所以要把类名字加上
        if (complex) {
            type = fixFieldType(type, currentPath);
        }
        String fixedName = type;
        classFieldDefine.setFieldType(fixedName);
        classFieldDefine.setClassTypeName(fixedName);

        String fieldName = AutoCodeUtil.firstLowerCase(originalType);
        classFieldDefine.setFieldName(fieldName);

        // 如果是可以重复的 就是一个List
        if (arrayType && classFieldDefine.getFieldType() != null &&
                !classFieldDefine.getFieldType().startsWith("List")) {
            classFieldDefine.setFieldType(type2List(classFieldDefine.getFieldType()));
        }
        classFieldDefine.setOriginJsonName(key);
        return classFieldDefine;
    }

    private String type2List(String type) {

        return String.format("List<%s>", type);
    }

    private String fixFieldType(String fieldType, String path) {

        if (path != null && path.contains(":")) {
            String[] arr = path.split(":");
            StringBuilder sb = new StringBuilder();
            for (String str : arr) {
                String newStr = AutoCodeUtil.firstUpper(str);
                newStr = AutoCodeUtil.preDealKey(newStr);
                sb.append(newStr);
            }
            return sb.toString();
        } else {
            return fieldType;
        }
    }

    private String generateClassName(String name) {

        return AutoCodeUtil.firstUpper(name);
    }

    private String generateClassName(JSONArray jsonArray, String name) {

        Object obj = jsonArray.get(0);
        if (obj instanceof JSONObject) {
            return AutoCodeUtil.firstUpper(name);
        } else if (obj instanceof JSONArray) {
            return AutoCodeUtil.firstUpper(name);
        } else if (obj instanceof String) {
            return "java.lang.String";
        } else if (obj instanceof Integer) {
            return "java.lang.Integer";
        } else if (obj instanceof Long) {
            return "java.lang.Long";
        } else if (obj instanceof Number) {
            return "java.math.BigDecimal";
        } else if (obj instanceof Boolean) {
            return "java.lang.Boolean";
        } else {
            return "java.lang.String";
        }
    }

}
